package com.ayou.binding;

import cn.hutool.core.util.ReflectUtil;
import com.ayou.executor.Executor;
import com.ayou.mapping.MappedStatement;
import com.ayou.mapping.SqlCommandType;
import com.ayou.session.Configuration;
import com.ayou.session.SqlSession;
import com.google.common.collect.Maps;
import com.ayou.annotations.Param;
import com.ayou.annotations.Select;
import com.ayou.parsing.GenericTokenParser;
import com.ayou.parsing.ParameterTokenHandler;
import com.ayou.type.IntegerTypeHandler;
import com.ayou.type.StringTypeHandler;
import com.ayou.type.TypeHandler;

import java.lang.reflect.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: mapper代理类
 * @author: ayouman
 * @date: 2024/6/28 17:46
 */
public class MapperProxy implements InvocationHandler {
    private SqlSession sqlSession;
    private Class mapperClass;

    public MapperProxy(SqlSession sqlSession, Class mapperClass) {
        this.sqlSession = sqlSession;
        this.mapperClass = mapperClass;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 设置参数值
        // TOTO:
        // 1. 没有使用param注解怎么搞
        // 2. 处理类型
        Map<String, Object> parameterValues = new HashMap<>();
        ;
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Param param = parameter.getAnnotation(Param.class);
            String paramName = param.value();
            parameterValues.put(paramName, args[i]);
        }

        String statementId = mapperClass.getName() + "." + method.getName();
        MappedStatement mappedStatement = sqlSession.getConfiguration().getMappedStatement(statementId);
        SqlCommandType sqlCommantType = mappedStatement.getSqlCommandType();
        Boolean selectMany = mappedStatement.getSelectMany();
        switch (sqlCommantType) {
            case SELECT:
                if (selectMany) {
                    return sqlSession.selectList(statementId, parameterValues);
                } else {
                    return sqlSession.selectOne(statementId, parameterValues);
                }
            case INSERT:
                return convertResult(mappedStatement, sqlSession.insert(statementId, parameterValues));
            case UPDATE:
                return convertResult(mappedStatement, sqlSession.update(statementId, parameterValues));
            case DELETE:
                return convertResult(mappedStatement, sqlSession.delete(statementId, parameterValues));
            default:
                break;
        }
        return null;
    }

    private Object convertResult(MappedStatement ms, int updateCount) {
        Class returnType = ms.getResultType();
        if (returnType == int.class || returnType == Integer.class) {
            return updateCount;
        } else if (returnType == long.class || returnType == Long.class) {
            return Long.valueOf(updateCount);
        } else if (returnType == void.class) {
            return null;
        }
        return null;
    }
}
